package com.hyy.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hyy.blog.api.BlogServiceApi;
import com.hyy.blog.api.pojo.BlogInfoResponse;
import com.hyy.common.constant.Constants;
import com.hyy.common.pojo.Result;
import com.hyy.common.utils.*;
import com.hyy.convert.BeanConvert;
import com.hyy.dataobject.UserInfo;
import com.hyy.common.exception.BlogException;
import com.hyy.mapper.UserInfoMapper;
import com.hyy.service.UserService;
import com.hyy.user.api.pojo.UserInfoRegisterRequest;
import com.hyy.user.api.pojo.UserInfoRequest;
import com.hyy.user.api.pojo.UserInfoResponse;
import com.hyy.user.api.pojo.UserLoginResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    @Qualifier("com.hyy.blog.api.BlogServiceApi")
    private BlogServiceApi blogServiceApi;

    @Autowired
    private RabbitTemplate rabbitTemplate;


    //已经配置自动装配
    // com.hyy.common.config.RedisConfig
// com.hyy.common.config.MailConfig
    @Autowired
    private Redis redis;

    private static final long EXPIRE_TIME = 14 * 24 * 60 * 60;

    private static final String USER_PREFIX = "user";

    /**
     * 用户登录方法
     * 验证用户名和密码，生成JWT令牌
     * @param user 登录请求参数
     * @return 登录响应，包含用户ID和JWT令牌
     */
    @Override
    public UserLoginResponse login(UserInfoRequest user) {
        //验证账号密码是否正确
        UserInfo userInfo = queryUserInfo(user.getUserName());
        if (userInfo == null || userInfo.getId() == null) {
            throw new BlogException("用户不存在");
        }


        if (!SecurityUtil.verify(user.getPassword(), userInfo.getPassword())) {
            throw new BlogException("用户密码不正确");
        }


        //账号密码正确的逻辑
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", userInfo.getId());
        claims.put("name", userInfo.getUserName());

        String jwt = JWTUtils.genJwt(claims);
        return new UserLoginResponse(userInfo.getId(), jwt);
    }

    /**
     * 获取用户信息
     * 根据用户ID查询用户详情
     * @param userId 用户ID
     * @return 用户信息响应
     */
    @Override
    public UserInfoResponse getUserInfo(Integer userId) {
        UserInfoResponse userInfoResponse = new UserInfoResponse();
        UserInfo userInfo = selectUserInfoById(userId);
        BeanUtils.copyProperties(userInfo, userInfoResponse);
        return userInfoResponse;
    }

    /**
     * 根据博客ID查询作者信息
     * 先通过BlogServiceApi获取博客详情，再根据作者ID查询作者信息
     * @param blogId 博客ID
     * @return 作者信息响应
     */
    @Override
    public UserInfoResponse selectAuthorInfoByBlogId(Integer blogId) {
        UserInfoResponse userInfoResponse = new UserInfoResponse();
        //1. 根据博客ID, 获取作者ID
        Result<BlogInfoResponse> blogDeatail = blogServiceApi.getBlogDeatail(blogId);
        //2. 根据作者ID, 获取作者信息
        if (blogDeatail == null || blogDeatail.getData() == null) {
            throw new BlogException("博客不存在");
        }
        UserInfo userInfo = selectUserInfoById(blogDeatail.getData().getUserId());
        BeanUtils.copyProperties(userInfo, userInfoResponse);
        return userInfoResponse;
    }

    /**
     * 查询用户信息
     * 先从Redis缓存中获取，如果没有则从数据库中获取并缓存到Redis
     * @param userName 用户名
     * @return 用户信息实体
     */
    private UserInfo queryUserInfo(String userName) {
        //先从redis中获取数据，redis中没有，再从数据库中获取
        String key = buildKey(userName);

        //不考虑redis查询异常的情况，因为异常 exits=false 按照逻辑自动去查询数据库
        boolean exits = redis.hasKey(key);
        if (exits) {
            log.info("从redis中获取用户信息,key:{}",key);
            //从redis中读取数据
            String userJson = redis.get(key);
            UserInfo userInfo = JsonUtil.parseJson(userJson, UserInfo.class);


            return userInfo == null ? selectUserInfoByName(userName) : userInfo;//查询失败，还是从数据库中查询
        } else {
            //从数据库中读取数据
            log.info("从mysql中获取用户信息，根据userName:{}",userName);

            UserInfo userInfo = selectUserInfoByName(userName);
            redis.set(key, JsonUtil.toJson(userInfo), EXPIRE_TIME);
            return userInfo;
        }
    }

    /**
     * 根据用户名查询用户信息
     * 从数据库中查询未删除的用户
     * @param userName 用户名
     * @return 用户信息实体
     */
    public UserInfo selectUserInfoByName(String userName) {
        return userInfoMapper.selectOne(new LambdaQueryWrapper<UserInfo>()
                .eq(UserInfo::getUserName, userName).eq(UserInfo::getDeleteFlag, 0));
    }

    /**
     * 根据用户ID查询用户信息
     * 从数据库中查询未删除的用户
     * @param userId 用户ID
     * @return 用户信息实体
     */
    private UserInfo selectUserInfoById(Integer userId) {
        return userInfoMapper.selectOne(new LambdaQueryWrapper<UserInfo>()
                .eq(UserInfo::getId, userId).eq(UserInfo::getDeleteFlag, 0));
    }

    /**
     * 用户注册方法
     * 校验参数，加密密码，保存用户信息，并发送消息到MQ通知发送邮件
     * @param registerRequest 注册请求参数
     * @return 注册成功的用户ID
     */
    @Override
    public Integer register(UserInfoRegisterRequest registerRequest) {
        //参数校验
        checkUserInfo(registerRequest);

        //用户注册（插入数据库）
        UserInfo userInfo = BeanConvert.convertUserInfoByEncrypt(registerRequest);
        int result = -1;
        try {
            result = userInfoMapper.insert(userInfo);

        } catch (Exception e) {
            log.error("用户注册失败：{}", e);
            throw new BlogException("用户注册失败");
        }
        if (result == 1) {
            //存储数据到Redis中
            //redis存储可能失败，查不到信息，就再mysql中去查询
            redis.set(buildKey(userInfo.getUserName()), JsonUtil.toJson(userInfo), EXPIRE_TIME);

            //注册成功后，发送消息给mq告诉消费者去发送邮件给用户
            userInfo.setPassword("");//为了保证安全 密码设置为空

            //指定把消息给到user exchange这个交换机 ，routingKey为空，因为是广播模式，最后一个参数是需要发送的消息
            rabbitTemplate.convertAndSend(Constants.USER_EXCHANGE_NAME,"",JsonUtil.toJson(userInfo));

            return userInfo.getId();
        } else {
            //插入失败
            throw new BlogException("用户注册失败");
        }
    }

    /**
     * 构建Redis键
     * 使用用户前缀和用户名生成Redis键
     * @param userName 用户名
     * @return Redis键
     */
    private String buildKey(String userName) {
        return redis.buildKey(USER_PREFIX, userName);
    }

    /**
     * 校验用户注册信息
     * 检查用户名是否重复、邮箱格式、GitHub URL格式是否合法
     * @param registerRequest 注册请求参数
     */
    private void checkUserInfo(UserInfoRegisterRequest registerRequest) {
        //用户名不能重复 邮箱格式 url格式
        UserInfo userInfo = selectUserInfoByName(registerRequest.getUserName());
        if (userInfo != null) {
            throw new BlogException("用户名已存在");
        }
        //TODO 邮箱 与 url
        if (!RegexUtil.checkMail(registerRequest.getEmail())) {
            throw new BlogException("邮箱格式不合法");
        }
     if(registerRequest.getGithubURL()!=""){
         if (!RegexUtil.checkURL(registerRequest.getGithubURL())) {
             throw new BlogException("githubUrl格式不合法");
         }
     }

    }

}
